#include "stdafx.h"
#include "..\headers\ColliderComponents.h"
#include "..\headers\VisualComponents.h"
#include "..\headers\PhysicsComponents.h"
#include "..\headers\PhysicsWorld.h"
#include "..\headers\GameObject.h"

namespace ne{

ColliderComponent::ColliderComponent():
m_shape(nullptr),m_compoundShape(nullptr),m_rigidBody(nullptr),m_index(0){
	m_type|=COMPONENT_COLLIDER;
}
ColliderComponent::~ColliderComponent(void){m_owner->Unregister(this);}

void ColliderComponent::Init(){
	m_physicsWorld=GameObject::GetPhysicsWorld();
	m_owner->Register(this);
}

void ColliderComponent::FinalizeCollider(){
	btTransform transform;
	transform.setIdentity();
	transform.setOrigin(btVector3(0.0f,0.0f,0.0f));
	RigidBodyComponent* rbc = nullptr;
	Component* comp = m_owner->GetComponent(COMPONENT_RIGIDBODY);
	if (comp == nullptr) {    // We need a rigid body component to create a collider so we will create a default static rigid body if none exists.
		rbc = static_cast<RigidBodyComponent*>(m_owner->AddComponent(COMPONENT_RIGIDBODY));
		rbc->SetStatic(true);
	}
	else {
		rbc = static_cast<RigidBodyComponent*>(comp);
	}
	m_rigidBody = rbc->GetRigidBody();
	m_compoundShape = rbc->GetCompoundShape();
	m_compoundShape->addChildShape(transform,m_shape);
	m_index = m_compoundShape->getNumChildShapes()-1;
	btVector3 inertia;
	m_compoundShape->calculateLocalInertia(rbc->GetMass(),inertia);
	
	m_rigidBody->setMassProps(rbc->GetMass(),inertia);
}

void ColliderComponent::Notify(CEvent* msg){
	if (msg->m_type==NE_MSG_REMOVE_COLLIDER){
		Shut();
	}
}

void ColliderComponent::Shut(){
	if (m_shape){
		m_compoundShape->removeChildShapeByIndex(m_index);
		delete m_shape;
		m_shape = nullptr;
	}
}

void ColliderComponent::SetOrigin(const Ogre::Vector3& p_origin){
	btTransform transform = m_compoundShape->getChildTransform(m_index);
	transform.setOrigin(Convert::ToBullet(p_origin));
	m_compoundShape->updateChildTransform(m_index, transform);
}

void ColliderComponent::SetRotation(const btQuaternion& rot){
	btTransform transform = m_compoundShape->getChildTransform(m_index);
	transform.setRotation(rot);
	m_compoundShape->updateChildTransform(m_index, transform);
}

void ColliderComponent::SetTransform(const btTransform& transform){
	m_compoundShape->updateChildTransform(m_index, transform);
}

void ColliderComponent::SetTransform(const btVector3& v, const btQuaternion& q){
	btTransform transform(q,v);
	m_compoundShape->updateChildTransform(m_index, transform);
}

const btVector3& ColliderComponent::GetOrigin(){
	return m_compoundShape->getChildTransform(m_index).getOrigin();
}

const btQuaternion ColliderComponent::GetRotation(){
	return m_compoundShape->getChildTransform(m_index).getRotation();
}

void BoxColliderComponent::Create(float x,float y,float z){
	m_shape = new btBoxShape(btVector3(x,y,z));
	FinalizeCollider();
}

void BoxColliderComponent::Create(const Ogre::Vector3& size){
	m_shape = new btBoxShape(Convert::ToBullet(size));
	FinalizeCollider();
}

void BoxColliderComponent::Create(){
	Component* comp = m_owner->GetComponent(COMPONENT_MESH);
	if (comp!=nullptr){
		BtOgre::StaticMeshToShapeConverter converter(static_cast<MeshComponent*>(comp)->GetEntity());
		m_shape = converter.createBox();
		FinalizeCollider();
	}
}

void SphereColliderComponent::Create(float radius){
	if(m_shape==nullptr){
		m_shape = new btSphereShape(radius);
		FinalizeCollider();
	}
}

void SphereColliderComponent::Create(){
	Component* comp = m_owner->GetComponent(COMPONENT_MESH);
	if (comp!=nullptr){
		BtOgre::StaticMeshToShapeConverter converter(static_cast<MeshComponent*>(comp)->GetEntity());
		m_shape = converter.createSphere();
		FinalizeCollider();
	}
}

StaticMeshColliderComponent::StaticMeshColliderComponent() : 
m_triangleMesh(nullptr){m_type|=COMPONENT_COLLIDER_STATIC_MESH;}
StaticMeshColliderComponent::~StaticMeshColliderComponent(){}

void StaticMeshColliderComponent::Create(){
	Component* comp = m_owner->GetComponent(COMPONENT_MESH);
	if (comp!=nullptr){
		BtOgre::StaticMeshToShapeConverter converter(static_cast<MeshComponent*>(comp)->GetEntity());
		BtOgre::TriangleMeshContainer container = converter.createTrimeshContainer();
		m_shape = container.triangle_mesh_shape;
		m_triangleMesh = container.triangle_mesh;
		FinalizeCollider();
	}
}

void StaticMeshColliderComponent::Notify(CEvent* msg){
	if (msg->m_type==NE_MSG_REMOVE_COLLIDER){
		Shut();
	}
}

void StaticMeshColliderComponent::Shut(){
	ColliderComponent::Shut();
	if (m_triangleMesh){
		delete m_triangleMesh;
		m_triangleMesh = nullptr;
	}
}

CapsuleColliderComponent::CapsuleColliderComponent(){m_type|=COMPONENT_COLLIDER_CAPSULE;}
CapsuleColliderComponent::~CapsuleColliderComponent(){}


void CapsuleColliderComponent::Create(float radius,float height){
	if(m_shape==nullptr){
		m_shape=new btCapsuleShape(radius,height);
		FinalizeCollider();
	}
}

void CapsuleColliderComponent::Create(){
	Component* comp = m_owner->GetComponent(COMPONENT_MESH);
	if (comp!=nullptr&&m_shape==nullptr){
		BtOgre::StaticMeshToShapeConverter converter(static_cast<MeshComponent*>(comp)->GetEntity());
		m_shape = converter.createCapsule();
		FinalizeCollider();
	}
}

}